package com.future.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.future.allUtils.constants.RedisCacheConstants;
import com.future.allUtils.utils.SecurityUtils;
import com.future.domain.*;
import com.future.domain.DTO.MembersDTO;
import com.future.domain.DTO.PageDTO;
import com.future.domain.DTO.PeopleDTO;
import com.future.mapper.ChatRoomMapper;
import com.future.mapper.ChatRoomMemberMapper;
import com.future.mapper.UserMapper;
import com.future.service.ChatMemberService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Time;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;



@Service
@Slf4j
public class ChatMemberServiceImpl implements ChatMemberService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private ChatRoomMapper chatRoomMapper;
    @Autowired
    private ChatRoomMemberMapper roomMemberMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveChatRoomMember(Long roomId, List<Long> userIds) {
        try {
            if (roomId != null && userIds != null && !userIds.isEmpty()) {
                // 1. 批量插入数据库（默认离线状态）
                roomMemberMapper.batchInsert(roomId, userIds);
                // 2. 更新Redis缓存（聊天室成员id）
                String memberKey = RedisCacheConstants.CHAT_ROOM_MEMBERS_PREFIX + roomId;
                String[] array = userIds.stream()
                        .map(String::valueOf)
                        .toArray(String[]::new);
                stringRedisTemplate.opsForSet().add(memberKey, array);
                stringRedisTemplate.expire(memberKey, RedisCacheConstants.CACHE_NORMAL_TTL, TimeUnit.SECONDS);
                //更新redis中聊天室成员列表
                String chatMembersKey = RedisCacheConstants.USER_CHAT_ROOMS_PREFIX + roomId;
                Set<String> memberDTOs = userIds.stream()
                        .map(user -> {
                            try {
                                MembersDTO membersDTO = roomMemberMapper.selectMemberDTO(user, roomId);
                                membersDTO.setRole(roomMemberMapper.selectRoleNamesByUserId(user));
                                return objectMapper.writeValueAsString(membersDTO);
                            } catch (JsonProcessingException e) {
                                log.error("消息序列化失败" + e);
                                return null;
                            }

                        })
                        .filter(Objects::nonNull) // 过滤序列化失败的对象
                        .collect(Collectors.toSet());
                stringRedisTemplate.opsForSet().add(chatMembersKey, memberDTOs.toArray(new String[0]));
                stringRedisTemplate.expire(chatMembersKey, 1, TimeUnit.DAYS);
            }
        } catch (Exception e) {
            log.error("保存聊天室成员失败", e);
            throw new RuntimeException("保存聊天室成员失败", e);
        }
    }

    @Override
    public Result getRoomMembers(String roomId1) {
        try {
            if (roomId1 == null || roomId1.trim().isEmpty()) {
                return Result.fail("房间号不能为空");
            }
            Long roomId = Long.valueOf(roomId1);
            ChatRoom chatRoom = chatRoomMapper.selectById(roomId);
            if (chatRoom == null) {
                return Result.fail("当前聊天室不存在");
            }
            // 1. 校验当前用户是否在该房间
            Long userId = SecurityUtils.getCurrentUserId();
            if (!checkUserInRoom(userId, roomId)) {
                return Result.fail("无权查看该聊天室成员");
            }
            //从redis中查询聊天室成员的列表
            String memberKey = RedisCacheConstants.USER_CHAT_ROOMS_PREFIX + roomId;
            Set<String> members = stringRedisTemplate.opsForSet().members(memberKey);
            if (members != null && !members.isEmpty()) {
                List<MembersDTO> memeberDTO = members.stream()
                        .map(memberdto -> {
                            try {
                                return objectMapper.readValue(memberdto, MembersDTO.class);
                            } catch (JsonProcessingException e) {
                                log.error("消息反序列化失败" + e);
                                return null;
                            }
                        })
                        .filter(Objects::nonNull)
                        .collect(Collectors.toList());
                List<Long> userIds = memeberDTO.stream()
                        .map(dto -> Long.parseLong(dto.getUserId()))
                        .collect(Collectors.toList());
                List<String> onlineKeys = userIds.stream()
                        .map(id -> RedisCacheConstants.USER_ONLINE_PREFIX + id)
                        .collect(Collectors.toList());
                //批量查询
                List<String> onlineStatusList = stringRedisTemplate.opsForValue().multiGet(onlineKeys);

                Map<Long, Integer> userIdToOnlineStatus = new HashMap<>();
                for (int i = 0; i < userIds.size(); i++) {
                    Long id = userIds.get(i);
                    String statusStr = onlineStatusList.get(i); // 可能为 null
                    int isOnline = (statusStr != null && "1".equals(statusStr)) ? 1 : 0;
                    userIdToOnlineStatus.put(id, isOnline);
                }
                for (MembersDTO member : memeberDTO) {
                    Long currentId = Long.valueOf(member.getUserId());
                    Integer isOnline = userIdToOnlineStatus.getOrDefault(currentId, 0);
                    member.setIsOnline(isOnline);
                }
                return Result.ok(memeberDTO);

            }
            // redis中没查到， 从数据库查询成员
            List<MembersDTO> memberDTOs = roomMemberMapper.selectRoomMemberDTOs(roomId);
            if (memberDTOs.isEmpty()) {
                return Result.ok(Collections.emptyList());
            }
            for(MembersDTO membersDTO:memberDTOs)
            {
               membersDTO.setRole(roomMemberMapper.selectRoleNamesByUserId(Long.valueOf(membersDTO.getUserId())));
            }
            //保存到redis中
            String chatMembersKey = RedisCacheConstants.USER_CHAT_ROOMS_PREFIX + roomId;
            Set<String> memberJsonSet = memberDTOs.stream()
                    .map(memberDTO -> {
                        try {
                            return objectMapper.writeValueAsString(memberDTO);
                        } catch (JsonProcessingException e) {
                            log.error("序列化成员信息失败", e); // 同理，用log记录失败，而非抛出异常
                            return null;
                        }
                    })
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());
            stringRedisTemplate.opsForSet().add(chatMembersKey, memberJsonSet.toArray(new String[0]));
            stringRedisTemplate.expire(chatMembersKey, 1, TimeUnit.DAYS);
            return Result.ok(memberDTOs);
        } catch (Exception e) {
            log.error("获取聊天室成员失败", e);
            return Result.fail("获取聊天室成员失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result addRoomMember(String roomId1, List<String> userIds1) {
        try {
            if (roomId1 == null || roomId1.trim().isEmpty()) {
                return Result.fail("房间号不能为空");
            }
            if (userIds1 == null || userIds1.isEmpty()) {
                return Result.fail("添加的用户列表不能为空");
            }
            Long roomId = Long.valueOf(roomId1);
            ChatRoom chatRoom1 = chatRoomMapper.selectById(roomId);
            if (chatRoom1 == null) {
                return Result.fail("聊天室不存在");
            }
            Long currentUserId = SecurityUtils.getCurrentUserId();
            if (currentUserId != null) {
                if (!currentUserId.equals(chatRoom1.getCreatedBy())) {
                    return Result.fail("非群主没有权限邀请别人");
                }
            }
            List<Long> userIds = userIds1.stream()
                    .map(Long::valueOf)
                    .collect(Collectors.toList());

            // 2. 过滤已存在的成员
            String memberKey = RedisCacheConstants.CHAT_ROOM_MEMBERS_PREFIX + roomId;
            Set<String> members = stringRedisTemplate.opsForSet().members(memberKey);
            if (members == null) {
                members = Collections.emptySet();
            }
            final List<Long> existingUserIds = new ArrayList<>();
            // 先添加Redis中查询到的成员
            existingUserIds.addAll(
                    members.stream()
                            .filter(Objects::nonNull)
                            .map(Long::valueOf)
                            .collect(Collectors.toList())
            );
            //如果redis未命中，查询数据库
            if (existingUserIds.isEmpty()) {
                List<Long> Ids = roomMemberMapper.selectUserIdByRoomId(roomId);
                //存入redis
                if (Ids != null && !Ids.isEmpty()) {
                    existingUserIds.addAll(Ids);
                    String[] array = Ids.stream()
                            .map(String::valueOf)
                            .toArray(String[]::new);
                    stringRedisTemplate.opsForSet().add(memberKey, array);
                    stringRedisTemplate.expire(memberKey, RedisCacheConstants.CACHE_NORMAL_TTL, TimeUnit.SECONDS);
                }
            }
            //过滤已存在的用户
            List<Long> newUserIds = userIds.stream()
                    .filter(userId -> !existingUserIds.contains(userId))
                    .collect(Collectors.toList());
            if (newUserIds.isEmpty()) {
                return Result.fail("用户都已在聊天室中");
            }
            // 3. 批量添加成员（默认离线状态）
            roomMemberMapper.batchInsert(roomId, userIds);
            // 4. 更新缓存
            String[] array = newUserIds.stream()
                    .map(String::valueOf)
                    .toArray(String[]::new);
            stringRedisTemplate.opsForSet().add(memberKey, array);
            stringRedisTemplate.expire(memberKey, 1, TimeUnit.DAYS);
            String memberDTOKey = RedisCacheConstants.USER_CHAT_ROOMS_PREFIX + roomId;
            Set<String> memberDTO = newUserIds.stream()
                    .map(userId -> {
                        try {
                            return objectMapper.writeValueAsString(roomMemberMapper.selectMemberDTO(userId, roomId));
                        } catch (JsonProcessingException e) {
                            log.error("消息序列化失败" + e);
                            return null;
                        }
                    })
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());
            stringRedisTemplate.opsForSet().add(memberDTOKey, memberDTO.toArray(new String[0]));
            stringRedisTemplate.expire(memberDTOKey, 1, TimeUnit.DAYS);
            //添加到班级
            Long classId = chatRoom1.getClassId();
            roomMemberMapper.savaClassMember(userIds, classId);
            return Result.ok("成功添加" + newUserIds.size() + "名成员");
        } catch (Exception e) {
            log.error("添加聊天室成员失败", e);
            throw new RuntimeException("添加聊天室成员失败：" + e.getMessage());

        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean insertMember(Long roomId, Long userId) {
        try {
            if (roomId == null) {
                return false;
            }
            if (userId == null) {
                return false;
            }
            ChatRoom chatRoom1 = chatRoomMapper.selectById(roomId);
            if (chatRoom1 == null) {
                return false;
            }
            // 2. 过滤已存在的成员
            String memberKey = RedisCacheConstants.CHAT_ROOM_MEMBERS_PREFIX + roomId;
            Set<String> members = stringRedisTemplate.opsForSet().members(memberKey);
            if (members == null) {
                members = Collections.emptySet();
            }
            final List<Long> existingUserIds = new ArrayList<>();
            // 先添加Redis中查询到的成员
            existingUserIds.addAll(
                    members.stream()
                            .filter(Objects::nonNull)
                            .map(Long::valueOf)
                            .collect(Collectors.toList())
            );
            //如果redis未命中，查询数据库
            if (existingUserIds.isEmpty()) {
                List<Long> Ids = roomMemberMapper.selectUserIdByRoomId(roomId);
                //存入redis
                if (Ids != null && !Ids.isEmpty()) {
                    existingUserIds.addAll(Ids);
                    String[] array = Ids.stream()
                            .map(String::valueOf)
                            .toArray(String[]::new);
                    stringRedisTemplate.opsForSet().add(memberKey, array);
                    stringRedisTemplate.expire(memberKey, RedisCacheConstants.CACHE_NORMAL_TTL, TimeUnit.SECONDS);
                }
            }
            if (existingUserIds.contains(userId)) {
                return false;
            }
            // 3. 添加成员（默认离线状态）
            roomMemberMapper.InsertMember(roomId, userId);
            // 4. 更新缓存
            stringRedisTemplate.opsForSet().add(memberKey, userId.toString());
            stringRedisTemplate.expire(memberKey, 1, TimeUnit.DAYS);
            String memberDTOKey = RedisCacheConstants.USER_CHAT_ROOMS_PREFIX + roomId;
            String memberDTO = objectMapper.writeValueAsString(roomMemberMapper.selectMemberDTO(userId, roomId));
            stringRedisTemplate.opsForSet().add(memberDTOKey, memberDTO);
            stringRedisTemplate.expire(memberDTOKey, 1, TimeUnit.DAYS);
            return true;
        } catch (Exception e) {
            log.error("添加聊天室成员失败", e);
            throw new RuntimeException("添加聊天室成员失败：" + e.getMessage());
        }
    }

    @Override
    public boolean removeRoomMember(Long userId, Long roomId) {
        try {
            if (userId == null) {
                return false;
            }
            if (roomId == null) {
                return false;
            }

            ChatRoom chatRoom = chatRoomMapper.selectById(roomId);
            if (chatRoom == null) {
                return false;
            }

            // 校验成员是否在房间中
            LambdaQueryWrapper<ChatRoomMember> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ChatRoomMember::getChatRoomId, roomId)
                    .eq(ChatRoomMember::getUserId, userId);
            ChatRoomMember member = roomMemberMapper.selectOne(queryWrapper);
            if (member == null) {
                return false;
            }
            // 4. 更新缓存
            String memberKey = RedisCacheConstants.CHAT_ROOM_MEMBERS_PREFIX + roomId;
            stringRedisTemplate.opsForSet().remove(memberKey, userId.toString());
            String memeberDTOKey = RedisCacheConstants.USER_CHAT_ROOMS_PREFIX + roomId;
            MembersDTO memberDTO = roomMemberMapper.selectMemberDTO(userId, roomId);
            if (memberDTO == null) {
                log.warn("未查询到用户{}在聊天室{}的DTO信息，无需删除DTO缓存", userId, roomId);
            } else {
                // 序列化并判空
                String memberstr = objectMapper.writeValueAsString(memberDTO);
                if (memberstr == null || memberstr.isEmpty()) {
                    log.warn("用户{}的DTO序列化结果为空，跳过删除", userId);
                } else {
                    Long dtoRemoveCount = stringRedisTemplate.opsForSet().remove(memeberDTOKey, memberstr);
                    log.info("删除聊天室{}成员DTO缓存，userId:{}，影响数量:{}", roomId, userId, dtoRemoveCount);
                }
            }
            // 移除成员
            roomMemberMapper.delete(queryWrapper);
            return true;
        }catch (Exception e)
        {
            log.error("移除聊天室失败");
            throw new RuntimeException(e);
        }
    }


    @Override
    public void updateUserOnlineStatus(Long userId, Integer isOnline) {
        try {
            if (userId == null || (isOnline != 0 && isOnline != 1)) {
                log.error("参数错误（isOnline必须为0或1）");
                return;
            }
            // 1. 更新Redis在线状态
            String onlineKey = RedisCacheConstants.USER_ONLINE_PREFIX + userId;
            stringRedisTemplate.opsForValue().set(onlineKey, isOnline.toString(), RedisCacheConstants.CACHE_LONG_TTL, TimeUnit.SECONDS);
            // 2. 同步更新数据库中所有聊天室的成员状态
            LambdaQueryWrapper<ChatRoomMember> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ChatRoomMember::getUserId, userId);
            List<ChatRoomMember> members = roomMemberMapper.selectList(queryWrapper);
            if (!members.isEmpty()) {
                members.forEach(member -> member.setIsOnline(isOnline));
                roomMemberMapper.batchUpdateIsOnline(members);
            }
            log.info("在线状态更新成功");
        } catch (Exception e) {
            log.error("更新在线状态失败", e);
        }
    }

    @Override
    public Result delectChatRoom(String roomId1) {
        try {
            if (roomId1 == null || roomId1.trim().isEmpty()) {
                return Result.fail("房间号为空");
            }
            Long roomId = Long.valueOf(roomId1);
            Long currentUserId = SecurityUtils.getCurrentUserId();
            //判断是不是聊天室成员
            LambdaQueryWrapper<ChatRoomMember> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ChatRoomMember::getChatRoomId, roomId)
                    .eq(ChatRoomMember::getUserId, currentUserId);
            ChatRoomMember member = roomMemberMapper.selectOne(queryWrapper);
            if (member == null) {
                return Result.fail("操作失败，不是聊天室成员");
            }
            //  更新缓存
            String memberKey = RedisCacheConstants.CHAT_ROOM_MEMBERS_PREFIX + roomId;
            stringRedisTemplate.delete(memberKey);
            String memeberDTOKey = RedisCacheConstants.USER_CHAT_ROOMS_PREFIX + roomId;
            stringRedisTemplate.delete(memeberDTOKey);
            //删除聊天室
            chatRoomMapper.deleteById(roomId);
            return Result.ok("删除成功");
    } catch(Exception e)
    {
        log.error("删除聊天室失败", e);
    }
        return Result.fail("删除聊天室失败");
}
    @Override
    public Result getUserOnlineStatus() {
        Long userId=SecurityUtils.getCurrentUserId();
        try {
            // 1. 校验用户是否存在
            User user = userMapper.selectById(userId);
            if (user == null) {
                return Result.ok("用户不存在"); // -1表示用户不存在
            }

            // 2. 优先从Redis获取在线状态
            String onlineKey = RedisCacheConstants.USER_ONLINE_PREFIX + userId;
            String statusStr = stringRedisTemplate.opsForValue().get(onlineKey);
            if (statusStr != null) {
                return Result.ok(Integer.parseInt(statusStr));
            }

            // 3. Redis无数据时，从数据库取最近状态
            List<ChatRoomMember> members = roomMemberMapper.selectList(
                    new LambdaQueryWrapper<ChatRoomMember>().eq(ChatRoomMember::getUserId, userId)
            );
            Integer status = members.isEmpty() ? 0 : members.get(0).getIsOnline();
            return Result.ok(status);
        } catch (Exception e) {
            log.error("获取在线状态失败", e);
            return Result.fail("获取在线状态失败：" + e.getMessage());
        }
    }

    @Override
    public Result selectByusername(String username) {
        List<PeopleDTO> membersDTOS = roomMemberMapper.selectUserByuserName(username);
        if(membersDTOS.isEmpty())
        {
            return Result.ok("未查询到相关用户");
        }
        return Result.ok(membersDTOS);
    }
    /**
     * 校验用户是否为聊天室成员
     */
    @Override
    public boolean checkUserInRoom(Long userId,Long roomId)
    {
        if(userId==null||roomId==null)
        {
            return false;
        }
        //先查redis缓存
        String chatMembersKey=RedisCacheConstants.CHAT_ROOM_MEMBERS_PREFIX+roomId;
        Boolean isMember=stringRedisTemplate.opsForSet().isMember(chatMembersKey,userId.toString());
        if(Boolean.TRUE.equals(isMember))
        {
            return true;
        }
        //缓存中没查到查数据库
        LambdaQueryWrapper<ChatRoomMember> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(ChatRoomMember::getUserId,userId)
                .eq(ChatRoomMember::getChatRoomId,roomId);
        ChatRoomMember member=roomMemberMapper.selectOne(queryWrapper);
        return member!=null;
    }
    /**
     * 未加入聊天室用户列表
     */
    @Override
    public Result unJoinChatRoom(Integer pageNum, Integer pageSize) {
        pageNum = (pageNum == null || pageNum < 1) ? 1 : pageNum;
        pageSize = (pageSize == null || pageSize < 1) ? 10 : pageSize;

        //未加入聊天室的列表
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        List<User> users = roomMemberMapper.selectUsersNeverJoined();
        List<Long> userIds = users.stream()
                .map(User::getId)
                .collect(Collectors.toList());
        Page<User> userPage = new Page<>(pageNum, pageSize);
        userQueryWrapper.in("id",userIds);
        userQueryWrapper.select("id", "username", "avatar", "bio");
        Page<User> resultPage = userMapper.selectPage(userPage,userQueryWrapper);
        PageDTO<PeopleDTO> pageDTO = PageDTO.of(resultPage, user -> new PeopleDTO(
                user.getAvatar(),   // PeopleDTO.avatar
                user.getId().toString(),       // PeopleDTO.userId
                user.getUsername(), // PeopleDTO.username
                user.getBio(),       // PeopleDTO.bio
                user.getCreatedAt()
        ));
        return Result.ok(pageDTO);
    }
    /**
     * 获取聊天室成员数
     */
    @Override
    public Result memberCount(String roomId1)
    {
        if(roomId1==null||roomId1.trim().isEmpty())
        {
            return Result.fail("房间号为空");
        }
        Long roomId=Long.valueOf(roomId1);
        ChatRoom chatRoom = chatRoomMapper.selectById(roomId);
        if(chatRoom==null)
        {
            return Result.fail("聊天室不存在");
        }
        //统计人数
        String chatMembersKey=RedisCacheConstants.USER_CHAT_ROOMS_PREFIX+roomId;
        //先查redis
        Long size = stringRedisTemplate.opsForSet().size(chatMembersKey);
        if(size!=null)
        {
            return Result.ok(size);
        }
        //redis未命中查询数据库
        Integer i = roomMemberMapper.countMembersByRoomId(roomId);
        Integer count=i==null?0:i;
        return Result.ok(count);
    }

    }

